﻿// Decompiled with JetBrains decompiler
// Type: Netick.ServerConnection
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System;
using System.Collections.Generic;

#nullable disable
namespace Netick;

public sealed class ServerConnection : NetworkConnection
{
  public readonly ServerSimulation.ClientData SimulationData;
  internal List<InterestManagementGroup> _interestGroups = new List<InterestManagementGroup>(128 /*0x80*/);
  internal List<AoIQuery> AoIQueries = new List<AoIQuery>(32 /*0x20*/);
  internal Tick BasisTickCur = Tick.InvalidTick;
  internal Tick LastSimTick = Tick.InvalidTick;
  internal bool DidWriteMetaLastTick;
  internal Packet[] PacketRecords;

  public IReadOnlyList<InterestManagementGroup> InterestGroups
  {
    get => (IReadOnlyList<InterestManagementGroup>) this._interestGroups;
  }

  public ServerConnection(short clientIndex, NetickEngine engine)
    : base(clientIndex, engine)
  {
    this.Index = (int) clientIndex;
    this.SimulationData = engine._srvSim.Clients[(int) clientIndex];
    this.PacketRecords = new Packet[engine.Config.MaxSnapshots];
    int capacity = Math.Min(1024 /*0x0400*/, engine.Config.MaxObjects + engine._IM.TotalGroupCount + 50);
    if (engine.AggressivePreAllocation)
      capacity = engine.Config.MaxObjects + engine._IM.TotalGroupCount + 50;
    for (int index = 0; index < this.PacketRecords.Length; ++index)
    {
      this.PacketRecords[index] = new Packet();
      this.PacketRecords[index].Allocate(capacity);
    }
  }

  ~ServerConnection()
  {
    for (int index = 0; index < this.PacketRecords.Length; ++index)
      this.PacketRecords[index].Deallocate();
  }

  internal override void OnDisconnected(
    TransportDisconnectReason transportDisconnectReason,
    bool releaseControlledEntities)
  {
    if (releaseControlledEntities)
      this.ReleaseControlledEntities();
    base.OnDisconnected(transportDisconnectReason, releaseControlledEntities);
  }

  internal override void Reset()
  {
    this.Engine._IM.ResetForClient(this.Index);
    this.SimulationData.Reset();
    base.Reset();
    this.BasisTickCur = Tick.InvalidTick;
    this.LastSimTick = Tick.InvalidTick;
    this.ReplicateEntities = true;
    for (int index = 0; index < this.PacketRecords.Length; ++index)
      this.PacketRecords[index].Clear();
  }

  internal override int WritePacketsSecondPass(SerializationCache cache)
  {
    this._writeBuffer.AddBool(this.ReplicateEntities);
    if (this.ReplicateEntities)
      Serialization.Write(this.Engine, cache, this, this._writeBuffer);
    return this._writeBuffer.Length();
  }

  internal override void ReadPayload(
    BitBuffer reader,
    Tick snapshotTick,
    Tick ackSnaphotTick,
    Tick lastSnapshotTick)
  {
    Tick tick = reader.ReadTick();
    int num1 = this.Engine._adaptiveReplicator != null ? this.Engine._adaptiveReplicator.Levels[this.Engine._adaptiveReplicator.LevelsCount - 1] : 1;
    if (tick % num1 == 0)
      this.BasisTickCur = tick;
    Tick snapTick = reader.ReadTick();
    int num2 = reader.ReadBool() ? 1 : 0;
    bool flag = reader.ReadBool();
    if (num2 != 0)
      this.SimulationData.OnClientReady();
    if (flag)
      this.SimulationData.Reset();
    this.Engine._sim.ReadInputs(this.Engine, this.Engine._reflectionData, this.Engine._srvSim.Clients[this.Index], reader);
    if ((!snapTick.IsValid ? 0 : (Math.Abs(this.Engine._snapshotTick - snapTick) < this.PacketRecords.Length - 5 ? 1 : 0)) != 0 && (snapTick > this.LastSimTick || !this.LastSimTick.IsValid))
    {
      this.LastSimTick = snapTick;
      this.Engine._internalReplicator.Entity.AP(this.Index, this.PacketRecords[this.LastSimTick % this.PacketRecords.Length].WorldRecord.RangeEnd, -1);
      if (snapTick % num1 == 0)
        this.OnAck(snapTick);
    }
    if (!ackSnaphotTick.IsValid)
      return;
    this.BasisSnapshotAck = ackSnaphotTick;
  }

  internal void OnAck(Tick snapTick)
  {
    int index = this.Index;
    Entity[] entitiesWorldIndexArray = this.Engine.Simulation.EntitiesWorldIndexArray;
    InterestManagementGroup[] allGroups = this.Engine._IM.AllGroups;
    Packet packetRecord = this.PacketRecords[snapTick % this.PacketRecords.Length];
    NativeArray<ObjectRecord> entities = packetRecord.Entities;
    int count = packetRecord.Count;
    for (int i = 0; i < count; ++i)
    {
      ObjectRecord objectRecord = entities[i];
      if (objectRecord.EntityId != -1)
      {
        if (objectRecord.IsIMGroup == 0)
        {
          Entity entity = entitiesWorldIndexArray[objectRecord.EntityWorldIndex];
          if (entity != null && entity.RawId == objectRecord.EntityId)
            entity.AP(index, objectRecord.RangeEnd, objectRecord.Tick);
        }
        else
          allGroups[objectRecord.EntityId].Entity.AP(index, objectRecord.RangeEnd, objectRecord.Tick);
      }
    }
  }

  internal void ReceiveAck(NetAck ack, int tickDiff)
  {
    if (this.Engine._snapshotTick - ack.Tick > this.Engine._config.MaxSnapshots - 5)
      this.Engine.Server.Kick(this);
    else
      this.RecvRootAck(ack, tickDiff);
  }

  internal void RecvRootAck(NetAck ack, int acks)
  {
    Tick tick = ack.Tick;
    bool flag1 = false;
    if (!ack.Tick.IsValid)
      return;
    if (!this.Ack.Tick.IsValid)
    {
      this.Ack.Tick = ack.Tick;
      acks = this.Ack.Tick - (this.FirstSentSnapshotTick - 1);
      flag1 = true;
    }
    else
      acks = tick - this.Ack.Tick;
    if (acks == 0)
      return;
    this.Ack.Tick = ack.Tick;
    int num = 0;
    if (flag1)
      return;
    for (int index = 0; index < acks; ++index)
    {
      bool flag2 = false;
      if (index > 31 /*0x1F*/)
        flag2 = true;
      Tick snapshotTick = tick - index;
      int offset = tick - snapshotTick;
      bool wasLost = flag2 | flag1 || !this.WasReceived(offset, ack.AckBitField);
      this.ProcessAck(snapshotTick, wasLost);
      if (wasLost)
        ++num;
    }
  }

  private bool WasReceived(int offset, uint ackBitfield)
  {
    return ((int) ackBitfield & 1 << offset) == 1 << offset;
  }

  private void ProcessAck(Tick snapshotTick, bool wasLost)
  {
  }
}
